/*
 * CX3K Scheduler
 * UMBC CMSC 345, FA2009
 * 
 * Group 6 (cmsc345group6@googlegroups.com)
 * Charles Crookes
 * Christopher Hayes
 * Christopher Thierer
 * Kyle Willett
 * 
 * Copyright 2009 by above individuals
 * Distributed under GNU General Public License, v2
 * Warranty information can be found at /warranty.txt
 * The GNU is available at /gpl-v2.txt
 */

package cx3k.dataaccess;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
 * The Database Manager handles connection to a database, supporting
 * the required functionality for a Manager.  The Database Manager uses
 * Hibernate to access the database, and to execute the required queries.  
 * Database connection information should be stored in the root of the source
 * directory in hbernate.cfg.xml.  
 * 
 * @author Chris Thierer
 *
 * @param <T> The type of objects being handled by this Database Manager.
 */
public abstract class DatabaseManager<T> implements Manager<T>{
	
	/**
	 * Logger object to handle log information.
	 */
	private static Logger logger = Logger.getLogger(DatabaseManager.class.getName());
	
	@Override
	public void delete(T delete){
				
		logger.info("Attempting to delete object from database...");
		
		if(delete != null){
			
			// get the Hibernate session and begin transaction
			Session session = getSession();
			Transaction tx = session.beginTransaction();
			
			try{
				session.delete(delete);
				tx.commit();
			}catch(HibernateException e){
				logger.error("Problem deleting the object.", e);
			} finally{
				// need to close the session
				session.close();
			}
			
		} else {
			logger.info("Attempted to delete null object, delete failed");
		}
		
	}
	
	@Override 
	public boolean save(T save){
		
		logger.info("Attempting to save to the database...");
		
		if(save != null){
			// get the Hibernate session and begin transaction
			Session session = getSession();
			Transaction tx = session.beginTransaction();
			
			// try to save or update the object specified 
			try{			
				session.saveOrUpdate(save);
				tx.commit();
			} catch(HibernateException e){
				logger.error("Problem saving the object.", e);			
				
				return false;
			} finally {
				// need to close the session
				session.close();
			}
		
			logger.info("Object " + save.toString() + " saved.");
			
			return true;
		} else {
			logger.info("Attempted to save null object, save failed.");
			
			return false;
		}
		
	}

	/**
	 * Open a session from the Hibernate Session Factory, which has been
	 * initialized to connect to the database.  This Session must be closed
	 * when it is completed. 
	 * @return 	A new session opened from the Hibernate Session Factory.
	 */
	protected static Session getSession(){
		return HibernateUtility.getSessionFactory().openSession();
	}

	/**
	 * Handles the initialization and serving of Hibernate Sessions.  The
	 * initialization of the Session Factory establishes a connection with the 
	 * database.  Connection parameters are defined in the hibernate.cfg.xml
	 * file, which is located in the root of the src directory.
	 * 
	 * @author Chris Thierer
	 *
	 */
	private static class HibernateUtility {
		
		/**
		 * The Session Factory built to serve sessions that are connected
		 * to the database specified by the configuration file.
		 */
		private static final SessionFactory sessionFactory = buildSessionFactory();
		
		/**
		 * Attempt to build the session factory.
		 * 
		 * @return 	An initialized Session Factory
		 */
		private static SessionFactory buildSessionFactory() {
			try {
				return new Configuration().configure().buildSessionFactory();
			} catch(Throwable ex){
				logger.error("Initial SessionFactory creation failed.", ex);
				throw new ExceptionInInitializerError(ex);
			}
		}
		
		/**
		 * @return	The initialized Session Factory, or null if the 
		 * 			connection was not created.
		 */
		public static SessionFactory getSessionFactory(){
			return sessionFactory;
		}
	}
}
